home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / c / gymake12.zip / MAKE.C < prev    next >
C/C++ Source or Header  |  1988-11-18  |  19KB  |  861 lines

  1. /*
  2.  * make.c    An imitation of the Unix MAKE facility
  3.  *
  4.  * 88-10-01 v1.0    created by greg yachuk, placed in the public domain
  5.  * 88-10-06 v1.1    changed prerequisite list handling
  6.  * 88-11-11 v1.2    fixed some bugs and added environment variables
  7.  *
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <errno.h>
  12. #include <fcntl.h>
  13. #include <string.h>
  14. #include <memory.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include <time.h>
  18. #ifdef    MSDOS
  19. #include <stdlib.h>
  20. #include <process.h>
  21. #include <dos.h>
  22. #else
  23. #include <sys/errno.h>
  24. #include <sys/wait.h>
  25. #endif
  26.  
  27. #include "make.h"
  28. #include "tstring.h"
  29. #include "decl.h"
  30.  
  31.  
  32. #ifdef    MSDOS
  33. #define    PATH_SEPARATOR    ";"
  34. #define    FILE_SEPARATOR    "/\\"
  35. #else
  36. #define    PATH_SEPARATOR    ":"
  37. #define    FILE_SEPARATOR    "/"
  38. #endif
  39.  
  40. #define MAKEINI "default.mk"
  41.  
  42. char   *shell_cmds[] = {
  43. #ifdef    MSDOS
  44.     "dir", "type", "rem", "pause", "date", "time", "ren", "rename",
  45.     "ver", "vol", "break", "verify", "mkdir", "md", "exit", "ctty",
  46.     "echo", "if", "cls", "chdir", "cd", "rmdir", "rd", "copy", "del",
  47.     "erase",
  48. #endif
  49.     NULL,
  50. };
  51.  
  52.  
  53. targptr target_list = NULL;    /* list of target nodes */
  54. fileptr file_list   = NULL;    /* list of file nodes */
  55. symptr  symbol_list = NULL;    /* list of symbol nodes */
  56. shellptr shell_list = NULL;    /* list of shell nodes */
  57.  
  58. int    make_level = 0;        /* for counting new_make()'s */
  59.  
  60. targptr first_targ = NULL;    /* first target, in case nothing explicit */
  61. targptr suffix_targ = NULL;    /* .SUFFIXES target pointer */
  62.  
  63. char  **tlist = NULL;        /* command line targets */
  64. char  **flist = NULL;        /* command line make files */
  65. char  **mlist = NULL;        /* command line macros */
  66.  
  67. int    tmax = 0;        /* max size of tlist */
  68. int    fmax = 0;        /* max size of flist */
  69. int    mmax = 0;        /* max size of mlist */
  70.  
  71. int    depend = 0;        /* -d option */
  72. int    display = 0;        /* -D option */
  73. int    envirn = 0;        /* -e option */
  74. int    ignore = 0;        /* -i option */
  75. int    noexec = 0;        /* -n option */
  76. int    readdef = 1;        /* -r option */
  77. int    silent = 0;        /* -s option */
  78. int    touch = 0;        /* -t option */
  79.  
  80. int    dispcount = 0;        /* used for -D option */
  81.  
  82. long    now;            /* time at startup */
  83. char   *makeflags;        /* value to update the MAKEFLAGS macro with */
  84.  
  85.  
  86. main(argc, argv)
  87. int     argc;
  88. char  **argv;
  89. {
  90.     REGISTER int i;
  91.     REGISTER targptr targp;
  92.     symptr    symp;
  93.     char   *envp;
  94.     char  **envv;
  95.  
  96.     /* initialize the various global lists */
  97.  
  98.     depend = 0;
  99.     dispcount = 0;
  100.  
  101.     target_list = NULL;
  102.     file_list = NULL;
  103.     shell_list = NULL;
  104.  
  105.     /* allocate space for command line targets, files and macros */
  106.  
  107.     tlist = grow_list(NULL, &tmax);
  108.     flist = grow_list(NULL, &fmax);
  109.     mlist = grow_list(NULL, &mmax);
  110.  
  111.     /* process MAKEFLAGS environment variable, first */
  112.  
  113.     symp = get_symbol("MAKEFLAGS", 0);
  114.     if (symp->svalue != NULL)
  115.     {
  116.         /* chop up the MAKEFLAGS and feed them to to make_args() */
  117.  
  118.         envp = tstrcpy(symp->svalue);
  119.         envv = tokenize(envp);
  120.         for (i=0; envv[i] != NULL; i++);
  121.         make_args(i, envv);
  122.  
  123.         /* free the vector of pointers, and the string itself, */
  124.         /* since you cannot have macros, targets or makefiles  */
  125.         /* in the MAKEFLAGS macro.                             */
  126.  
  127.         tfree(envv);
  128.         tfree(envp);
  129.         tfree(makeflags);    /* ignore this, since we just read it */
  130.     }
  131.  
  132.     make_args(--argc, ++argv);    /* process command line options */
  133.  
  134.     add_macro(makeflags, 0);    /* update the MAKEFLAGS macro */
  135.     tfree(makeflags);
  136.  
  137.     /* add command line macros, so they DON'T get overridden */
  138.  
  139.     for(i = 0; mlist[i] != NULL; i++)
  140.         add_macro(mlist[i], 1);
  141.  
  142.     tfree(mlist);            /* all done with macros */
  143.  
  144.     if (noexec)
  145.         silent = touch = 0;    /* -n always displays; never touches */
  146.  
  147.     if (dispcount > 1)
  148.         display = 1;        /* display `default.mk' on -DD */
  149.  
  150.     first_targ = NULL;        /* used in parse() */
  151.  
  152.     if (readdef)
  153.         parse(fopenp(MAKEINI, "r"));    /* read in `default.mk' */
  154.  
  155.     if (dispcount > 0)
  156.         display = 1;        /* display makefile's on -D */
  157.  
  158.     first_targ = NULL;        /* get first target in `makefile' */
  159.  
  160.     /* parse the makefiles given on command line */
  161.     for(i = 0; flist[i] != NULL; i++)
  162.     {
  163.         parse(equal(flist[i],"-") ? fdopen(dup(fileno(stdin)), "r")
  164.                       : fopen(flist[i], "r"));
  165.     }
  166.  
  167.     /* no makefiles specified, so use "makefile" */
  168.     if (i == 0)
  169.         parse(fopen("makefile", "r"));
  170.  
  171.     tfree(flist);            /* all done with makefile's */
  172.  
  173.     if ((targp = get_target(".INIT")) != NULL)
  174.         build(targp->tshell);    /* process the .INIT rule */
  175.  
  176.     for (i = 0; tlist[i] != NULL; i++)
  177.         make(tlist[i], 1);    /* process command line targets */
  178.  
  179.     tfree(tlist);            /* all done with targets */
  180.  
  181.     /* if no targets specified, make the first one */
  182.     if (i == 0 && first_targ)
  183.         make(first_targ->tfile->fname, 1);
  184.  
  185.     if ((targp = get_target(".DONE")) != NULL)
  186.         build(targp->tshell);    /* process the .DONE rule */
  187.  
  188.     return (0);            /* not exit(); see new_make() */
  189. }
  190.  
  191.  
  192. /*
  193.  * make_args    - process the command line arguments
  194.  */
  195. make_args(argc, argv)
  196. int    argc;
  197. char  **argv;
  198. {
  199.     REGISTER int tlen;
  200.     REGISTER int flen;
  201.     REGISTER int mlen;
  202.     char   *tmf;
  203.  
  204.     now = time(NULL);        /* get current date & time */
  205.  
  206.     makeflags = tstrcpy("MAKEFLAGS+=");
  207.  
  208.     tlen = flen = mlen = 0;
  209.  
  210.     for (;argc != 0; ++argv, --argc)
  211.     {
  212.         if (**argv != '-')
  213.         {
  214.             /* doesn't start with '-'; must be macro or target */
  215.  
  216.             if (strchr(*argv, '='))
  217.             {        /* store as a macro */
  218.                 if (mlen == mmax)
  219.                     mlist = grow_list(mlist, &mmax);
  220.                 mlist[mlen++] = *argv;
  221.             }
  222.             else
  223.             {        /* store as a target */
  224.                 if (tlen == tmax)
  225.                     tlist = grow_list(tlist, &tmax);
  226.                 tlist[tlen++] = *argv;
  227.             }
  228.             continue;
  229.         }
  230.  
  231.         /* must be an option */
  232.  
  233.         tmf = tstrcat(makeflags, *argv);
  234.         tfree(makeflags);
  235.         makeflags = tstrcat(tmf, " ");
  236.         tfree(tmf);
  237.  
  238.         while (*argv && *++*argv)
  239.         {
  240.             switch (**argv)
  241.             {
  242.             case 'd':        /* show dependencies */
  243.                 depend++;
  244.                 break;
  245.  
  246.             case 'D':        /* display makefiles */
  247.                 dispcount++;
  248.                 break;
  249.  
  250.             case 'e':        /* don't override environment */
  251.                 envirn = 1;
  252.                 break;
  253.  
  254.             case 'f':        /* new makefile name */
  255.                 if (argc < 2)
  256.                     usage();
  257.                 if (flen == fmax)
  258.                     flist = grow_list(flist, &fmax);
  259.                 ++argv, --argc;
  260.                 flist[flen++] = *argv;
  261.  
  262.                 /* save, but ignore, the makefile */
  263.                 tmf = tstrcat(makeflags, *argv);
  264.                 tfree(makeflags);
  265.                 makeflags = tstrcat(tmf, " ");
  266.                 tfree(tmf);
  267.  
  268.                 *argv = NULL;
  269.                 break;
  270.  
  271.             case 'i':        /* ignore errors */
  272.                 ignore = 1;
  273.                 break;
  274.  
  275.             case 'n':        /* don't execute commands */
  276.                 noexec = 1;
  277.                 break;
  278.  
  279.             case 'r':        /* don't read default.mk */
  280.                 readdef = 0;
  281.                 break;
  282.  
  283.             case 's':        /* don't echo commands */
  284.                 silent = 1;
  285.                 break;
  286.  
  287.             case 't':        /* touch files, don't build */
  288.                 touch = 1;
  289.                 break;
  290.  
  291.             default:
  292.                 usage();    /* never returns */
  293.             }
  294.         }
  295.     }
  296.  
  297.     /* terminate all lists with a NULL pointer */
  298.  
  299.     tlist[tlen] = NULL;
  300.     flist[flen] = NULL;
  301.     mlist[mlen] = NULL;
  302.  
  303.     /* let the caller update the makeflags macro */
  304. }
  305.  
  306.  
  307. /*
  308.  * grow_list    - expand the list of pointers by a factor of two
  309.  */
  310. char  **
  311. grow_list(list, len)
  312. char  **list;
  313. int    *len;
  314. {
  315.     REGISTER int l;
  316.  
  317.     l = *len;        /* get current length */
  318.  
  319.     /* if list is NULL, start off with a default list */
  320.  
  321.     if (list == NULL)
  322.         list = (char **) talloc(((l=1)+1) * sizeof(char *));
  323.     else
  324.         list = (char **) trealloc((char *)list,
  325.                       ((l <<=1)+1)*sizeof(char *));
  326.  
  327.     if (list == NULL)
  328.         terror(1, "too many options");
  329.  
  330.     /* if we are initially allocating it, set first pointer to NULL */
  331.  
  332.     if (l == 1)
  333.         *list = NULL;
  334.  
  335.     *len = l;        /* update current length */
  336.     return (list);
  337. }
  338.  
  339.  
  340. /*
  341.  * fopenp    - open file in current directory or along PATH
  342.  */
  343. FILE   *
  344. fopenp(fname, type)
  345. char   *fname;
  346. char   *type;
  347. {
  348.     REGISTER int len;
  349.     REGISTER char *fpath;
  350.     FILE   *fd;
  351.     char   *path;
  352.     char   *tp;
  353.  
  354.     /* try to open file relative to current directory */
  355.     if ((fd = fopen(fname, type)) != NULL)
  356.         return (fd);
  357.  
  358.     /* didn't work, search along path */
  359.  
  360.     if ((path = getenv("PATH")) == NULL)
  361.         return (NULL);
  362.  
  363.     path = tstrcpy(path);        /* allocate string and copy */
  364.     fpath = talloc(strlen(path) + strlen(fname) + 2);
  365.  
  366.     /